package com.rabbit.many.config;

import org.springframework.amqp.rabbit.config.RetryInterceptorBuilder;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * MQ 工厂配置类
 *
 * @Author su
 * @Date 2022/7/22 11:36
 */
@Configuration
public class MQFactoryConfig {

    @Autowired
    private MQProperties rabbitMqProperties;

    //线程数量:根据实际的服务器性能进行配置即可
    public static final int DEFAULT_CONCURRENT = 10;
    //最大线程数
    public static final int MAX_CONCURRENT = 48;

    /**
     * 默认连接工厂
     *
     * @return
     */
    @Primary //这个注解一定要加 Rabbitmq需要一个默认的 工厂
    @Bean(name = "defaultConnectionFactory")
    public ConnectionFactory defaultConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(rabbitMqProperties.getDefaultHost());
        connectionFactory.setPort(rabbitMqProperties.getDefaultPort());
        connectionFactory.setUsername(rabbitMqProperties.getDefaultUsername());
        connectionFactory.setPassword(rabbitMqProperties.getDefaultPassword());
        return connectionFactory;
    }


    /**
     * 默认容器工厂
     *
     * @param configurer
     * @param connectionFactory
     * @return
     */
    @Primary //这个注解一定要加 Rabbitmq需要一个默认的 工厂
    @Bean(name = "defaultFactory")
    public SimpleRabbitListenerContainerFactory defaultFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, @Qualifier("defaultConnectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 指定要创建的并发消费者数量   默认值为1
        factory.setConcurrentConsumers(DEFAULT_CONCURRENT);
        // 设置消费者数量的上限
        factory.setMaxConcurrentConsumers(MAX_CONCURRENT);
        // 自动应答
        // factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //消息转换器
        //factory.setMessageConverter(new Jackson2JsonMessageConverter());
        //启动事务模式
        //factory.setChannelTransacted(true);
        //设置重试
        factory.setAdviceChain(createRetry());
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    /**
     * 创建重试
     *
     * @return
     */
    private RetryOperationsInterceptor createRetry() {
        RetryTemplate retryTemplate = new RetryTemplate();

        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(3000); // 重试间隔
        backOffPolicy.setMaxInterval(6000); // 重试最大间隔
        //backOffPolicy.setMultiplier(2000);// 重试间隔乘法策略
        retryTemplate.setBackOffPolicy(backOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(3);
        retryTemplate.setRetryPolicy(retryPolicy);
        return RetryInterceptorBuilder.stateless().retryOperations(retryTemplate).recoverer(new RejectAndDontRequeueRecoverer()).build();
    }

    /**
     * 默认RabbitTemplate操作类
     *
     * @param connectionFactory
     * @return
     */
    @Primary//这个注解一定要加 Rabbitmq需要一个默认的 工厂
    @Bean(name = "defaultTemplate")
    public RabbitTemplate defaultTemplate(@Qualifier("defaultConnectionFactory") ConnectionFactory connectionFactory) {
        return new RabbitTemplate(connectionFactory);
    }

    @Primary//这个注解一定要加 Rabbitmq需要一个默认的 工厂
    @Bean(name = "defaultRabbitAdmin")
    public RabbitAdmin defaultRabbitAdmin(@Qualifier("defaultConnectionFactory") ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    /**
     * MQ 2 连接工厂
     *
     * @return
     */
    @Bean(name = "twoConnectionFactory")
    public ConnectionFactory MergeConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(rabbitMqProperties.getTwoHost());
        connectionFactory.setPort(rabbitMqProperties.getTwoPort());
        connectionFactory.setUsername(rabbitMqProperties.getTwoUsername());
        connectionFactory.setPassword(rabbitMqProperties.getTwoPassword());
        return connectionFactory;
    }

    /**
     * MQ 2 容器工厂
     *
     * @param configurer
     * @param connectionFactory
     * @return
     */
    @Bean(name = "twoFactory")
    public SimpleRabbitListenerContainerFactory LocalFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, @Qualifier("twoConnectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        //设置线程数量
        factory.setConcurrentConsumers(DEFAULT_CONCURRENT);
        factory.setMaxConcurrentConsumers(MAX_CONCURRENT);
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    /**
     * MQ 2 操作类
     *
     * @param connectionFactory
     * @return
     */
    @Bean(name = "twoTemplate")
    public RabbitTemplate TwoTemplate(@Qualifier("twoConnectionFactory") ConnectionFactory connectionFactory) {
        return new RabbitTemplate(connectionFactory);
    }

    @Bean(name = "twoRabbitAdmin")
    public RabbitAdmin twoRabbitAdmin(@Qualifier("twoConnectionFactory") ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }
}
